Email Notification Add-on Installer =================================== ⚠️ Only Seeq Administrators can run this installer to completion, since only Administrators can install Add-ons. If you are using Seeq’s SaaS product, instead of this Data Lab-based notification mechanism, it is recommended that you utilize the built in notification capabilities in Seeq R60+ as described in the following Seeq Knowledge Base article: https://telemetry.seeq.com/support-link/kb/latest/cloud/notifications-on-conditions This notebook will walk you through the steps needed to install the Email Notification Scheduler as a Data Lab Tool in Workbench. If you are fine with the defaults and have never installed the scheduler before, you should be able to leave everything as is, running all cells in order. At the end, if you have encountered no errors: \* in the folder you’ve specified using the ``path_to_notifications_folder``, you should find all files listed as ``source_files`` below \* the Tools tab in Workbench should have a tool grouping named ``Add-ons`` \* there should be a tool named ``Email Notification Scheduler`` among the ``Add-ons``. There is ONE MORE STEP that must be done to complete installation - after running all steps in this installer, one must complete the SMTP server and account configuration in ``Email Notifier.ipynb`` within the target folder (``Email Notifications`` if ``path_to_notifications_folder`` is not changed below). Please note that anyone that has access to this project will be able to see the account information provided there. If using the gmail SMTP server, it is preferred to use an app password rather than the actual password for the account, and the port should be set to 587 to use STARTTLS. You can find out more about gmail app passwords in the `Google Account Help `__. See the `Add-on Tools KB article `__ for further details of Add-on tools. Installation Folder ~~~~~~~~~~~~~~~~~~~ The path to the Notifications folder is set in the next cell. It should be specified relative to the root of the project and should use forward slashes ( / ) for path separators. The folder should be created before proceeding with installation. .. code:: ipython3 path_to_notifications_folder = 'Email Notifications' How to handle existing files ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If the following parameter is changed to ``True``, any existing files in the target folder will be overwritten. You may want to do this if you wish to discard changes to the installed notebooks or if you wish to upgrade the notebooks with the versions found in this folder (e.g., after upgrading the Data Lab server). .. code:: ipython3 overwrite_existing_files = False How to handle existing versions of Scheduler in Add-on Tools ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If the following parameter is ``True``, any already-installed tools with the same name as shown in the ``name`` field of the ``tool_with_permissions`` dictionary below will be removed before the new tool is installed. By default, the ``name`` of the scheduler is ``Email Notification Scheduler``. Be careful! If you change this parameter to ``True``, you will be replacing the existing version of the Add-on Tool with the version found at the ``path_to_notifications_folder`` in this project for *all users* of the Add-on Tool. You may want to change the ``name`` field in the ``tool_with_permissions`` dictionary instead. .. code:: ipython3 remove_existing_versions = False Tool Configuration ~~~~~~~~~~~~~~~~~~ Check the output of the following cell to confirm the desired configuration for the Add-on Tool. The resulting JSON object will be used to create or update the existing tool. .. code:: ipython3 import urllib.parse as urlparse target_path_encoded = urlparse.quote(path_to_notifications_folder) project_id = spy.utils.get_data_lab_project_id() project_url = spy.utils.get_data_lab_project_url() notebook_name = 'Email Notification Scheduler.ipynb' query_parameters = '?workbookId={workbookId}&worksheetId={worksheetId}&workstepId={workstepId}&seeqVersion={seeqVersion}' install_url = f'{project_url}/addon/{path_to_notifications_folder}/{notebook_name}/{query_parameters}' tool_with_permissions = { 'name': 'Email Notification Scheduler', 'description': 'Data Lab Notebook-based Email Notification Scheduling tool', 'iconClass': 'fa fa-envelope', 'targetUrl': install_url, 'linkType': 'window', 'windowDetails': 'toolbar=0,location=0,scrollbars=1,statusbar=0,menubar=0,resizable=1,height=700,width=600', 'sortKey' : 'e', 'reuseWindow': 'false', # but not relevant, since linkType is 'tab' 'permissions': { 'groups': [], 'users': [spy.user.email] } } print('The following parameters will be used to define the add-on:\n') tool_with_permissions ⚠️ Advanced Configuration and Automated Installation Beyond This Point ---------------------------------------------------------------------- If you are just running this notebook to install or update the Email Notifications Scheduler in a typical fashion, you can just run the remaining cells as is, checking the output of each to confirm the expected results. Contact support if any problems are encountered. .. code:: ipython3 import os import requests import shutil from datetime import datetime, timezone from pathlib import Path from seeq import sdk try: spy_version = seeq.__version__ except: spy_version = spy.__version__ print(f'Seeq PyPI package version: {spy_version}') Check whether the required source files and target folder exist ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The source files should be in the same folder as this installer. The target folder for the installation should already exist by the time this installer is run. .. code:: ipython3 home_path = os.environ['HOME'] all_required_paths_exist = False source_files = [ 'Email Notification Scheduler.ipynb', 'Email Notifier.ipynb', 'Email Unsubscriber.ipynb', 'Seeq Data Lab.jpg' ] source_paths = [ f'{os.getcwd()}/{source_file}' for source_file in source_files ] target_folder_path = Path(home_path, path_to_notifications_folder) os.makedirs(target_folder_path, exist_ok=True) target_folder_exists = os.path.exists(target_folder_path) all_source_paths_exist = all(iter([os.path.exists(source_path) for source_path in source_paths])) status_message = '' if not all_source_paths_exist: files_string = "\n".join(source_paths) status_message += f'Not all source files exist. Check for the presence of the following files ' \ f'in the folder that contains this notebook:\n{source_files}' if not target_folder_exists: status_message += f'Target folder not found. Add a folder at {path_to_notifications_folder} relative to ' \ f'the root of the Data Lab Project' if status_message: print(status_message) else: print('All required paths exist. Installation may proceed.') .. code:: ipython3 target_paths = [] if all_source_paths_exist: existing_files_not_overwritten = False for source_path in source_paths: source_file = source_path.split('/').pop() target_path = Path(home_path, path_to_notifications_folder, source_file) target_paths.append(target_path) if overwrite_existing_files or not target_path.exists(): shutil.copyfile(source_path, target_path) else: existing_files_not_overwritten = True if existing_files_not_overwritten: print(f'Warning! One or more files were not overwritten. Change overwrite_existing_files to True ' f'or delete the files in the target folder to ensure the latest versions.') all_target_files_exist = all(iter([os.path.exists(target_path) for target_path in target_paths])) print(f'{"All" if all_target_files_exist else "Not all"} target files exist. ' f'Installation may{" " if all_target_files_exist else " not "}proceed.') else: all_target_files_exist = False print('Please check results of previous step') Configuration update and tool installation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The following cell enables the Add-on Tools and ScheduledNotebooks features and adds the Email Notifications Scheduler to the Add-on Tools. .. code:: ipython3 # Adapted from the Notebook Add-on Tool Management UI-TEST.ipynb, available at # https://seeq.atlassian.net/wiki/spaces/SQ/pages/961675391/Add-on+Tools def create_add_on_tool(tool_with_permissions): # Create add-on tool tool = tool_with_permissions.copy() tool.pop("permissions") tool_id = sdk.SystemApi(spy.client).create_add_on_tool(body = tool).id items_api = sdk.ItemsApi(spy.client) # assign group permissions to add-on tool and data lab project groups = tool_with_permissions["permissions"]["groups"] for group_name in groups: group = sdk.UserGroupsApi(spy.client).get_user_groups(name_search=group_name) if group: ace_input = { 'identityId': group.items[0].id, 'permissions': { 'read': True } } # Add permissions to add-on tool item items_api.add_access_control_entry(id=tool_id, body=ace_input) # Add permissions to data lab project if target URL references one ace_input['permissions']['write'] = True # Data lab project also needs write permission items_api.add_access_control_entry(id=project_id, body=ace_input) # assign user permissions to add-on tool and data lab project users = tool_with_permissions["permissions"]["users"] for user_name in users: user = sdk.UsersApi(spy.client).get_users(username_search=user_name) if user: ace_input = { 'identityId': user.users[0].id, 'permissions': { 'read': True } } items_api.add_access_control_entry(id=tool_id, body=ace_input) # Add permissions to data lab project if target URL references one ace_input['permissions']['write'] = True # Data lab project also needs write permission items_api.add_access_control_entry(id=project_id, body=ace_input) system_api = sdk.SystemApi(spy.client) if all_target_files_exist: if not spy.user.is_admin: raise RuntimeError('Only Administrators can install Add-on Tools') if int(spy_version.split('.')[0]) >= 54: configuration_output = system_api.get_configuration_options(limit=5000) else: configuration_output = system_api.get_configuration_options() add_on_tools_already_enabled = next((option.value for option in configuration_output.configuration_options if option.path == 'Features/AddOnTools/Enabled'), False) scheduled_notebooks_already_enabled = next((option.value for option in configuration_output.configuration_options if option.path == 'Features/DataLab/ScheduledNotebooks/Enabled'), False) configuration_options_update = [] if not add_on_tools_already_enabled: configuration_options_update.append( sdk.ConfigurationOptionInputV1( note = f'Set to true by Email Notifications Installer user {spy.user.email} {datetime.now(timezone.utc)}', path = 'Features/AddOnTools/Enabled', value = True ) ) if not scheduled_notebooks_already_enabled: configuration_options_update.append( sdk.ConfigurationOptionInputV1( note = f'Set to true by Email Notifications Installer user {spy.user.email} {datetime.now(timezone.utc)}', path = 'Features/DataLab/ScheduledNotebooks/Enabled', value = True ) ) if configuration_options_update: config_options = sdk.ConfigurationInputV1(configuration_options = configuration_options_update) system_api.set_configuration_options(body=config_options) existing_tools_output = system_api.get_add_on_tools() existing_tools = [add_on_tool for add_on_tool in existing_tools_output.add_on_tools if add_on_tool.name == tool_with_permissions['name']] if len(existing_tools) > 0: if not remove_existing_versions: raise RuntimeError(f'One or more tools exist with name {tool_with_permissions["name"]}, ' f'and remove_existing_versions is False; Cannot create add-on tool') else: # Delete existing tools for existing_tool in existing_tools: system_api.delete_add_on_tool(id=existing_tool.id) print(f'Removed {len(existing_tools)} existing tools with name {tool_with_permissions["name"]}') # Create new tool create_add_on_tool(tool_with_permissions) print(f'Success! Check Workbench for the {tool_with_permissions["name"]} tool in the Add-on Tools collection') else: print('Not all target files exist; cannot complete installation.')